package com.xuetao.spider.util;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.CodingErrorAction;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.net.ssl.SSLContext;

import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Description
 * @Author xuetao wang
 * @Date 2021/3/31
 *
 * 设置好小红书的请求头
 */

public class ApiConnector {
    private static final Logger logger = LoggerFactory.getLogger(ApiConnector.class);

    private static PoolingHttpClientConnectionManager connManager = null;
    private static CloseableHttpClient httpclient = null;

    private static Header USER_AGENT = new BasicHeader(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36");

    private static Header UpgradeInsecureRequests = new BasicHeader("Upgrade-Insecure-Requests", "1");
    private static Header Referer = new BasicHeader("Referer", "https://www.xiaohongshu.com/web-login/canvas?redirectPath=http%3A%2F%2Fwww.xiaohongshu.com%2Fuser%2Fprofile%2F58c4fcde6a6a691cfb4087bb");
    private static Header Host = new BasicHeader("Host", "www.xiaohongshu.com");
    private static Header Accept = new BasicHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
    private static Header AcceptEncoding = new BasicHeader("Accept-Encoding", "gzip, deflate, br");
    private static Header AcceptLanguage = new BasicHeader("Accept-Language", "en,zh-CN;q=0.9,zh;q=0.8");

    private static Header Cookie = new BasicHeader("Cookie", "xhsTracker=url=index&searchengine=google; xhsTrackerId=e2382287-8789-4d07-cdc6-928dc27bd769; xhsuid=tzDr1eiMtgwLb363; timestamp2=20210330f61571ed7e842bb9d36855c0; timestamp2.sig=4c2SpPsK79Gg5ek6BZLG3ayRP-mE6eXMtrDMeenx8ro; extra_exp_ids=gif_clt1,ques_exp1");


    /**
     * 最大连接数
     */
    public final static int MAX_TOTAL_CONNECTIONS = 800;
    /**
     * 获取连接的最大等待时间
     */
    public final static int WAIT_TIMEOUT = 60000;
    /**
     * 每个路由最大连接数
     */
    public final static int MAX_ROUTE_CONNECTIONS = 400;
    /**
     * 连接超时时间
     */
    public final static int CONNECT_TIMEOUT = 30000;

    static SSLConnectionSocketFactory sslsf = null;

    static {
        try {
            SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {

                @Override
                public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                    return true;
                }
            }).build();

            sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
                    SSLConnectionSocketFactory.getDefaultHostnameVerifier());

        } catch (Exception e) {
            e.printStackTrace();
        }

        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE).register("https", sslsf).build();

        connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

        // Create socket configuration
        SocketConfig socketConfig = SocketConfig.custom().setTcpNoDelay(true).build();

        connManager.setDefaultSocketConfig(socketConfig);

        ConnectionConfig connectionConfig = ConnectionConfig.custom().setMalformedInputAction(CodingErrorAction.IGNORE)
                .setUnmappableInputAction(CodingErrorAction.IGNORE).setCharset(Consts.UTF_8)
                .build();
        connManager.setDefaultConnectionConfig(connectionConfig);
        connManager.setMaxTotal(MAX_TOTAL_CONNECTIONS);
        connManager.setDefaultMaxPerRoute(MAX_ROUTE_CONNECTIONS);

        httpclient = HttpClients.custom().setConnectionManager(connManager)
                .setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE)
                .setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)
                .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
                .build();
    }

    public static String get(String url) {
        return get(url, null, "UTF-8");
    }

    @SuppressWarnings("deprecation")
    public static String get(String url, List<NameValuePair> pairs, String encode) {
        String responseString = null;
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(CONNECT_TIMEOUT)
                .setConnectTimeout(CONNECT_TIMEOUT).setConnectionRequestTimeout(CONNECT_TIMEOUT).build();

        StringBuilder sb = new StringBuilder();
        sb.append(url.trim());
        int i = 0;
        if (pairs != null && pairs.size() > 0) {
            for (NameValuePair entry : pairs) {
                if (i == 0 && !url.contains("?")) {
                    sb.append("?");
                } else {
                    sb.append("&");
                }
                sb.append(entry.getName());
                sb.append("=");
                String value = entry.getValue();
                try {
                    sb.append(URLEncoder.encode(value, "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    logger.warn("encode http get params error, value is {}", value, e);
                    sb.append(URLEncoder.encode(value));
                }
                i++;
            }
        }

//        logger.info("[HttpUtils Get] begin invoke:" + url.toString());

        HttpGet get = new HttpGet(url.toString());

        get.setConfig(requestConfig);

        get.addHeader(USER_AGENT);
        get.addHeader(UpgradeInsecureRequests);
        get.addHeader(Referer);
        get.addHeader(Host);
        get.addHeader(Accept);
        get.addHeader(AcceptEncoding);
        get.addHeader(AcceptLanguage);
        get.addHeader(Cookie);

        try {
            long s1 = System.currentTimeMillis();
            CloseableHttpResponse response = httpclient.execute(get);
            long s2 = System.currentTimeMillis();
            try {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode != HttpStatus.SC_OK) {
                    get.abort();
                    logger.error("[HttpUtils Get] error, url : {}  , params : {},  status :{}", url, pairs, statusCode);
                    return "";
                }

                HttpEntity entity = response.getEntity();
                try {
                    if (entity != null) {
                        responseString = EntityUtils.toString(entity, encode);
                    }
                } finally {
                    if (entity != null) {
                        entity.getContent().close();
                    }
                }
            } catch (Exception e) {
                logger.error("[HttpUtils Get]get response error, url:{}", url.toString(), e);
                return responseString;
            } finally {
                if (response != null) {
                    response.close();
                }
            }

        } catch (Exception e) {
            logger.error("[HttpUtils Get] error, url : {}  , params : {}, response string : {} ,error : {}", url, pairs,
                    "", e.getMessage(), e);
        } finally {
            get.releaseConnection();
        }
        return responseString;
    }
}
